package com.arpa.wms.service;

import cn.hutool.core.collection.IterUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.arpa.core.web.Result;
import com.arpa.ntocc.common.common.cache.ShipmentCache;
import com.arpa.ntocc.common.common.exception.ServiceException;
import com.arpa.ntocc.common.common.util.UserUtil;
import com.arpa.ntocc.common.domain.entity.Shipment;
import com.arpa.wms.cache.CarrierCache;
import com.arpa.wms.cache.ShopCache;
import com.arpa.wms.common.ess.*;
import com.arpa.wms.common.util.ArpaCloudUtil;
import com.arpa.wms.common.util.TypeUtil;
import com.arpa.wms.domain.consts.CommonConst;
import com.arpa.wms.domain.consts.NumConst;
import com.arpa.wms.domain.consts.ResultDO;
import com.arpa.wms.domain.entity.Carrier;
import com.arpa.wms.domain.entity.Delivery;
import com.arpa.wms.domain.entity.DeliveryItem;
import com.arpa.wms.domain.entity.Shop;
import com.arpa.wms.domain.enums.ErpTypeEnum;
import com.arpa.wms.domain.enums.SourcePlatformEnum;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.taobao.pac.sdk.cp.PacClient;
import com.taobao.pac.sdk.cp.SendSysParams;
import com.taobao.pac.sdk.cp.dataobject.request.CLOUDPRINT_STANDARD_TEMPLATES.CloudprintStandardTemplatesRequest;
import com.taobao.pac.sdk.cp.dataobject.request.TMS_WAYBILL_DISCARD.TmsWaybillDiscardRequest;
import com.taobao.pac.sdk.cp.dataobject.response.CLOUDPRINT_STANDARD_TEMPLATES.CloudprintStandardTemplatesResponse;
import com.taobao.pac.sdk.cp.dataobject.response.CLOUDPRINT_STANDARD_TEMPLATES.StandardTemplateResult;
import com.taobao.pac.sdk.cp.dataobject.response.TMS_WAYBILL_DISCARD.TmsWaybillDiscardResponse;
import lombok.extern.log4j.Log4j2;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.AsyncResult;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.time.ZoneOffset;
import java.util.*;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

import static com.arpa.wms.domain.consts.NumConst.NUM_ONE;
import static com.arpa.wms.domain.consts.TipConst.*;
import static java.util.stream.Collectors.toList;

/**
 * @author liuxr
 * @date 2021年05月10日 14:00
 */
@Log4j2
@Service
public class TmsWaybillUpdateService {
    /**
     * 测试环境请求url
     */
    @Value("${taobao.wly.dailyUrl}")
    private String dailyUrl;
    @Resource
    private ArpaCloudUtil arpaCloudUtil;
    @Resource
    private CarrierCache carrierCache;
    @Resource
    private ShopCache shopCache;
    @Autowired
    private IDeliveryService deliveryService;
    @Autowired
    private IDeliveryItemService deliveryItemService;
    @Autowired
    private ShipmentCache shipmentCache;


    /**
     * 取消面单
     * @author liuxr
     * @date 2021/5/10 15:41
     * @param deliveryCode
     */
    @Transactional(rollbackFor = Exception.class)
    public void tmsWaybillDiscard(String deliveryCode) {
        Delivery deliveries = deliveryService.getOne(new LambdaQueryWrapper<Delivery>().eq(Delivery::getCode,deliveryCode).eq(Delivery::getGroupCode,UserUtil.getBranchCode()));
        if(null==deliveries){

            throw new ServiceException("电子面单取消失败：找不到订单信息");
        }
        Carrier carrier =carrierCache.getCarrier(deliveries.getCarrierCode());
        if(carrier==null){
            throw new ServiceException("电子面单取消失败：找不到承运商信息");
        }
        PacClient client = new PacClient(carrier.getQimenKey(), carrier.getWaybillPassword(), dailyUrl);
        SendSysParams params = new SendSysParams();
        Shop shop = shopCache.getShop(carrier.getShopCode());
        if (null != shop) {
            params.setFromCode(shop.getAccessToken());
        }
        TmsWaybillDiscardRequest request = new TmsWaybillDiscardRequest();
        //配送公司编码
        request.setCpCode(deliveries.getLogisticsCode());
        request.setWaybillCode(deliveries.getWaybillCode());

        TmsWaybillDiscardResponse tmsWaybillDiscardResponse = client.send(request, params);
        if(!tmsWaybillDiscardResponse.isSuccess()){
            log.info("errorCode:" + tmsWaybillDiscardResponse.getErrorCode() + ",errorMessage:" + tmsWaybillDiscardResponse.getErrorMsg());
            throw new ServiceException("电子面单取消失败："+ tmsWaybillDiscardResponse.getErrorMsg());
        }

        deliveryService.waybillDiscard(deliveryCode);
    }

    public void waybillDiscard(PacClient client,SendSysParams params ,String logisticsCode,String waybillCode){
        if(StrUtil.hasBlank(logisticsCode,waybillCode)){
            log.info("电子面单取消失败，参数为空: logisticsCode:{}；waybillCode:{}",logisticsCode,waybillCode );
            return;
        }

        TmsWaybillDiscardRequest request = new TmsWaybillDiscardRequest();
        //配送公司编码
        request.setCpCode(logisticsCode);
        request.setWaybillCode(waybillCode);

        TmsWaybillDiscardResponse tmsWaybillDiscardResponse = client.send(request, params);
        if(tmsWaybillDiscardResponse.isSuccess()){
            log.info("电子面单取消成功: logisticsCode:{}；waybillCode:{}",logisticsCode,waybillCode );
        }else{

            log.error("电子面单取消失败: errorCode:" + tmsWaybillDiscardResponse.getErrorCode() + ",errorMessage:" + tmsWaybillDiscardResponse.getErrorMsg());
        }
    }
    /**
     * 获取快递标准模板
     * @author liuxr
     * @date 2021/6/10 12:36
     * @param key
     * @param secret
     * @param token
     * @return java.util.List<com.taobao.pac.sdk.cp.dataobject.response.CLOUDPRINT_STANDARD_TEMPLATES.StandardTemplateResult>
     */
    public List<StandardTemplateResult> getCloudprintStandardTemplates(String key, String secret , String token , String logisticsCode){
        PacClient client = new PacClient(key, secret, dailyUrl);
        SendSysParams params = new SendSysParams();
        params.setFromCode(token);
        CloudprintStandardTemplatesRequest request1 = new CloudprintStandardTemplatesRequest();
        request1.setCpCode(logisticsCode);
        CloudprintStandardTemplatesResponse cloudprintStandardTemplatesResponse = client.send(request1, params);
        if(cloudprintStandardTemplatesResponse.isSuccess()){
            List<StandardTemplateResult> obj =  cloudprintStandardTemplatesResponse.getData();
            return obj;
        }
        return null;
    }

/*    @Async
    public void asyncTmsWaybillDiscard(List<Delivery > deliveries){

        if(IterUtil.isEmpty(deliveries)){
            return;
        }
       Set<String> carrierCodeSet = deliveries.stream().map(Delivery::getCarrierCode).collect(Collectors.toSet());
        if(carrierCodeSet.size()>0){

            return;
        }
        Carrier carrier =iCarrierService.getOne(new LambdaQueryWrapper<Carrier>().in(Carrier::getCode,carrierCodeSet).last(" limit 1"));
        if(carrier==null){
            return;
        }
        PacClient client = new PacClient(carrier.getQimenKey(), carrier.getWaybillPassword(), dailyUrl);
        SendSysParams params = new SendSysParams();
        params.setFromCode(carrier.getWaybillCustomerCode());

        deliveries.parallelStream().forEach(r-> this.waybillDiscard(client,params,r.getLogisticsCode(),r.getWaybillCode()));
    }*/

    /**
     * 批量获取面单号
     *
     * @param deliveryCodes 订单号
     */
    @Async
    public String batchGetWaybillCode(List<String> deliveryCodes,String groupCode) {
        log.info("批量获取面单号，订单号：{}",JSONUtil.toJsonStr(deliveryCodes));
        List<Delivery> deliveryList = deliveryService.list(new LambdaQueryWrapper<Delivery>()
                .eq(Delivery::getGroupCode,groupCode)
                .eq(Delivery::getIsCancel,NumConst.NUM_ZERO)
                .select(Delivery::getId,
                        Delivery::getCode,
                        Delivery::getCarrierType,
                        Delivery::getWaybillCode,
                        Delivery::getLogisticsCode,
                        Delivery::getShipmentCode,
                        Delivery::getCarrierCode,
                        Delivery::getSenderProvince,
                        Delivery::getSenderCity,
                        Delivery::getSenderDistrict,
                        Delivery::getSenderDetailAddress,
                        Delivery::getSenderName,
                        Delivery::getSenderMobile,
                        Delivery::getSourceType,
                        Delivery::getDeliveryOrderCode,
                        Delivery::getSourcePlatformCode,
                        Delivery::getReceiverProvince,
                        Delivery::getReceiverCity,
                        Delivery::getReceiverDistrict,
                        Delivery::getReceiverDetailAddress,
                        Delivery::getReceiverName,
                        Delivery::getReceiverMobile,
                        Delivery::getIsvCode,
                        Delivery::getUserId,
                        Delivery::getOaid,
                        Delivery::getTid,
                        Delivery::getStatus,
                        Delivery::getIsCancel
                )
                .in(Delivery::getCode, deliveryCodes));
        List<String> deliveryOrderCode =  deliveryList.stream().map(Delivery::getDeliveryOrderCode).collect(toList());

        log.info("批量获取面单号的订单列表:{}", JSONUtil.toJsonStr(deliveryList));
        log.info("批量获取面单号【1】，过滤是否有物流承运商");
        List<Delivery> logisticsDeliveryList = deliveryList.stream().filter(d -> StrUtil.equals(d.getCarrierType(), "logistics")).collect(toList());
        if (IterUtil.isNotEmpty(logisticsDeliveryList)) {
            List<String> codes = logisticsDeliveryList.stream().map(Delivery::getCode).collect(toList());
            log.info("批量获取面单号【1】，所选订单包含物流承运商，不能获取面单号。{}", codes);
            deliveryService.updateFailureReasonOfGetWaybillCode(deliveryCodes, "所选订单包含物流承运商，不能获取面单号",groupCode);
            throw new ServiceException("所选订单【" + codes + "】承运商为物流，无法获取面单号");
        }
        log.info("批量获取面单号【2】，过滤是否有快递承运商");
        List<Delivery> expressDeliveryList = deliveryList.stream().filter(d -> StrUtil.equals(d.getCarrierType(), "express")).collect(toList());
        if (IterUtil.isEmpty(expressDeliveryList)) {
            log.info("批量获取面单号【2】，所选订单包含没有承运商，不能获取面单号。{}", deliveryCodes);
            deliveryService.updateFailureReasonOfGetWaybillCode(deliveryCodes, "所选订单包含没有承运商，不能获取面单号",groupCode);
            throw new ServiceException("所选订单【" + deliveryCodes + "】没有承运商，无法获取面单号");
        }


        //面单号校验，如果面单号有非空的，则提示
        log.info("批量获取面单号【3】，过滤是已有面单号");
        List<Delivery> tempDeliveryList = expressDeliveryList.stream()
                .filter(item -> StrUtil.isNotBlank(item.getWaybillCode())).collect(Collectors.toList());

        if (IterUtil.isNotEmpty(tempDeliveryList)) {

            List<String> codes = tempDeliveryList.stream().map(Delivery::getCode).collect(toList());
            deliveryService.updateFailureReasonOfGetWaybillCode(deliveryCodes, "所选订单【" + codes + "】已有面单号，无法获取面单号",groupCode);
            throw new ServiceException("所选订单【" + codes + "】已有面单号，无法获取面单号");
        }
        //获取面单号为空的订单
        deliveryList = expressDeliveryList.stream().filter(item -> StrUtil.isBlank(item.getWaybillCode())).collect(Collectors.toList());
        if (IterUtil.isEmpty(deliveryList)) {
            log.info("批量获取面单号【4】，没有符合获取面单要求的，不能获取面单号。{}", deliveryCodes);
            deliveryService.updateFailureReasonOfGetWaybillCode(deliveryCodes, "没有复合获取面单要求的，不能获取面单号",groupCode);
            throw new ServiceException("所选订单【" + deliveryCodes + "】没有符合获取面单要求的，无法获取面单号");
        }


        // 校验是否都是同一承运商
        int logisticsSize = deliveryList.stream().collect(Collectors.groupingBy(Delivery::getCarrierCode)).size();
        if (logisticsSize > NUM_ONE) {
            deliveryService.updateFailureReasonOfGetWaybillCode(deliveryCodes, MUST + CHOOSE + SAME + LOGISTICS_NAME + DELIVERY,groupCode);
            throw new ServiceException(MUST + CHOOSE + SAME + LOGISTICS_NAME + DELIVERY);
        }
        // 校验是否都是同一货主
        int shipmentSize = deliveryList.stream().collect(Collectors.groupingBy(Delivery::getShipmentCode)).size();
        if (shipmentSize > NUM_ONE) {
            deliveryService.updateFailureReasonOfGetWaybillCode(deliveryCodes, MUST + CHOOSE + SAME + SHIPMENT_NAME + DELIVERY,groupCode);
            throw new ServiceException(MUST + CHOOSE + SAME + SHIPMENT_NAME + DELIVERY);
        }
        Carrier carriers = carrierCache.getCarrier(deliveryList.get(0).getCarrierCode());
        if (null == carriers) {
            log.error("找不到承运商信息，无法获取面单号。");
            deliveryService.updateFailureReasonOfGetWaybillCode(deliveryCodes, "找不到承运商信息，无法获取面单号。",groupCode);
            throw new ServiceException("找不到承运商信息");
        }

        //重新赋值店铺授权token
        String shopCode = carriers.getShopCode();
        if(StrUtil.isBlank(shopCode)){
            log.error("找不到承运商对应的店铺信息，无法获取面单号。");
            deliveryService.updateFailureReasonOfGetWaybillCode(deliveryCodes, "找不到承运商对应的店铺信息，无法获取面单号。",groupCode);
            throw new ServiceException("找不到承运商对应的店铺信息");
        }
        Shop shop = shopCache.getShop(shopCode);
        if(null==shop){
            log.error("找不到承运商对应的店铺信息，无法获取面单号。");
            deliveryService.updateFailureReasonOfGetWaybillCode(deliveryCodes, "找不到承运商对应的店铺信息，无法获取面单号。",groupCode);
            throw new ServiceException("找不到承运商对应的店铺信息");
        }
        if(StrUtil.isEmpty(shop.getAccessToken())){
            log.error("承运商绑定的店铺accessToken为空，无法获取面单号。");
            deliveryService.updateFailureReasonOfGetWaybillCode(deliveryCodes, "承运商绑定的店铺accessToken为空，无法获取面单号。",groupCode);
            throw new ServiceException("承运商绑定的店铺accessToken为空，无法获取面单号。");
        }
        //客户token
        String dynamicToken = shop.getAccessToken();

        int type = 1;
        switch (carriers.getPlatformType()){
            case "JD":{
                Set<String> sourcePlatformCodeSet = deliveryList.stream().map(Delivery::getSourcePlatformCode).collect(Collectors.toSet());
                if(sourcePlatformCodeSet.size() > NUM_ONE||!sourcePlatformCodeSet.contains("JD")){
                    deliveryService.updateFailureReasonOfGetWaybillCode(deliveryCodes, "订单销售平台与承运商平台类型不匹配",groupCode);
                    throw new ServiceException("订单销售平台与承运商平台类型不匹配");
                }
                type = 2;
                //TODO 调用京东接口
                break;
            }
            case "PDD": {
                Set<String> sourcePlatformCodeSet = deliveryList.stream()
                        .map(Delivery::getSourcePlatformCode).collect(Collectors.toSet());
                if (sourcePlatformCodeSet.size() > NUM_ONE || !(sourcePlatformCodeSet.contains("PDD") || sourcePlatformCodeSet.contains("PIN_DUO_DUO"))) {
                    deliveryService.updateFailureReasonOfGetWaybillCode(deliveryCodes, "订单销售平台与承运商平台类型不匹配",groupCode);
                    throw new ServiceException("订单销售平台与承运商平台类型不匹配");
                }
                type = 3;
                break;
            }
            case "DY": {
                Set<String> sourcePlatformCodeSet = deliveryList.stream()
                        .map(Delivery::getSourcePlatformCode).collect(Collectors.toSet());
                if (sourcePlatformCodeSet.size() > NUM_ONE || !(sourcePlatformCodeSet.contains("DY") || sourcePlatformCodeSet.contains("DYXD"))) {
                    deliveryService.updateFailureReasonOfGetWaybillCode(deliveryCodes, "订单销售平台与承运商平台类型不匹配",groupCode);
                    throw new ServiceException("订单销售平台与承运商平台类型不匹配");
                }
                type = 4;
                break;
            }
            case "TB": {
              /*  Set<String> sourcePlatformCodeSet = deliveryList.stream()
                        .map(Delivery::getSourcePlatformCode).collect(Collectors.toSet());*/
                /*if (sourcePlatformCodeSet.size() > NUM_ONE || !(sourcePlatformCodeSet.contains("TB") || sourcePlatformCodeSet.contains("TM"))) {
                    deliveryService.updateFailureReasonOfGetWaybillCode(deliveryCodes, "订单销售平台与承运商平台类型不匹配");
                    throw new ServiceException("订单销售平台与承运商平台类型不匹配");
                }*/
                type = 5;
                break;
            }
            case "KS": {
                Set<String> sourcePlatformCodeSet = deliveryList.stream()
                        .map(Delivery::getSourcePlatformCode).collect(Collectors.toSet());
                if (sourcePlatformCodeSet.size() > NUM_ONE || !(sourcePlatformCodeSet.contains("KS") || sourcePlatformCodeSet.contains("KUAI_SHOU"))) {
                    deliveryService.updateFailureReasonOfGetWaybillCode(deliveryCodes, "订单销售平台与承运商平台类型不匹配",groupCode);
                    throw new ServiceException("订单销售平台与承运商平台类型不匹配");
                }
                type = 6;
                break;
            }
            default: {

                type = 1;
            }
        }

        List<Integer> failCodes = Lists.newArrayList();
        // 线程结果集
        Map<Integer, Future<Boolean>> futureMap = Maps.newHashMap();
        //承运商外部编码（快递编码）
        String outerCode = carriers.getOuterCode();
        //模板地址
        String standardTemplateUrl = carriers.getStandardTemplateUrl();

        if (StrUtil.hasBlank(dynamicToken, outerCode)) {
            log.error("无法获取面单号，承运商缺少必须要信息。{}", carriers);
            deliveryService.updateFailureReasonOfGetWaybillCode(deliveryCodes, "无法获取面单号，承运商缺少必须要信息。",groupCode);
            throw new ServiceException("无法获取面单号，承运商缺少必须要信息。");
        }

        //将查出来所有得订单号，按10条分组
        List<List<Delivery>> deliveries = Lists.partition(deliveryList, 10);

        for (List<Delivery> delivers : deliveries) {
            ElectronicFaceSheetDTO dto = genElectronicFaceSheetDTO(carriers, delivers, dynamicToken, outerCode, standardTemplateUrl, type, shop,groupCode);
            List<String> codes = delivers.stream().map(Delivery::getCode).collect(toList());
            Future<Boolean> future = batchGetWaybillCodeByDeliverys(dto, groupCode, codes);
            if (future == null) {
                failCodes.add(codes.hashCode());
            } else {
                futureMap.put(codes.hashCode(), future);
            }
        }
        StringBuilder failMsg = new StringBuilder();
        futureMap.forEach((key, future) -> {
            try {
                while (true) {
                    if (future.isDone()) {
                        Boolean status = future.get();
                        if (!status) {
                            failCodes.add(key);
                        }
                        break;
                    }
                }
            } catch (ServiceException | InterruptedException | ExecutionException e) {
                failMsg.append("订单:").append(key).append("异常信息:").append(e.getMessage()).append(";");
                failCodes.add(key);
                Thread.currentThread().interrupt();
            }
        });

        //将订单任务状态更新为执行完成
        deliveryService.update(new LambdaUpdateWrapper<Delivery>()
                .in(Delivery::getCode, deliveryCodes).eq(Delivery::getGroupCode, groupCode)
                .set(Delivery::getTaskStatus, CommonConst.STR_THREE)
        );

        return failMsg.toString();

    }


    public ElectronicFaceSheetDTO genElectronicFaceSheetDTO(Carrier carriers, List<Delivery> deliverys, String dynamicToken,
                                                            String outCode, String standardTemplateUrl, int type, Shop shop,String groupCode) {
        ElectronicFaceSheetDTO dto = new ElectronicFaceSheetDTO();
        dto.setType(type);
        Delivery delivery = deliverys.get(0);
        // 寄件地址，这里的地址需要是卖家订购电子面单服务时使用的订购地址，具体可以通过TMS_WAYBILL_SUBSCRIPTION_QUERY接口获取
        AddressDto sendAddress = new AddressDto();
        sendAddress.setProvince(carriers.getProvince());
        sendAddress.setCity(carriers.getCity());
        sendAddress.setDistrict(carriers.getCounty());
        sendAddress.setDetail(carriers.getAddress());

        // 发件人信息
        UserInfoDto sender = new UserInfoDto();
        // 发件人姓名
        sender.setName(delivery.getSenderName());
        // 发件人手机号
        sender.setMobile(delivery.getSenderMobile());
        sender.setPhone(delivery.getSenderMobile());
        sender.setAddress(sendAddress);
        //sender.setOaid(delivery.getOaid());
        //sender.setTid(delivery.getTid());


        // 配送公司编码
        dto.setCpCode(outCode);
        //顺丰快递时，传入顺丰品牌编码
        if (StrUtil.isNotEmpty(carriers.getBrandCode())) {
            dto.setBrandCode(carriers.getBrandCode());
        }
        if (StrUtil.isNotEmpty(carriers.getCustomerCode())) {
            dto.setCustomerCode(carriers.getCustomerCode());
        }
        dto.setSender(sender);
        dto.setDynamicToken(dynamicToken);

        ArrayList<TradeOrderInfoDto> orderInfoDtos = new ArrayList<>();

        List<String> deliveryCodes = deliverys.stream().map(Delivery::getCode).collect(Collectors.toList());
        Map<String, List<DeliveryItem>> deliveryItemsMap = new HashMap<>();
        if (IterUtil.isNotEmpty(deliveryCodes)) {
            List<DeliveryItem> deliveryItems = this.deliveryItemService.list(new LambdaQueryWrapper<DeliveryItem>()
                    .eq(DeliveryItem::getGroupCode,groupCode)
                    .in(DeliveryItem::getDeliveryCode, deliveryCodes));
            if (IterUtil.isNotEmpty(deliveryItems)) {
                deliveryItemsMap = deliveryItems.stream().collect(Collectors.groupingBy(DeliveryItem::getDeliveryCode));
            } else {
                deliveryService.updateFailureReasonOfGetWaybillCode(deliveryCodes, "找不到订单明细，订单：" + JSONUtil.toJsonStr(deliveryCodes),groupCode);
                throw new ServiceException("找不到订单明细，订单：" + JSONUtil.toJsonStr(deliveryCodes));
            }
        } else {
            throw new ServiceException("获取面单失败，订单号不存在");
        }

        Map<String, List<DeliveryItem>> finalDeliveryItemsMap = deliveryItemsMap;
        Map<String,Object> shipmentMap = shipmentCache.get(carriers.getShipmentCode());
        deliverys.forEach(e -> {
            //处理erp推单在isvCode添加字符情况
            handleIsvCode(e,shipmentMap);
            //处理合单的问题
            hedan(e);
            ArrayList<String> orderList = new ArrayList<>();
            if (StrUtil.equals(e.getSourceType(), "qimen")) {
                // 订单列表，这里的场景是一个订单获取一个面单号
                switch (type) {
                    case 2:
                    case 4:
                    case 6:
                        orderList.add(e.getIsvCode());
                        break;
                    case 5:
                        orderList.add(e.getIsvCode());
                        break;
                    default:
                        orderList.add(e.getDeliveryOrderCode());
                }
            } else {
                orderList.add(e.getCode());
            }

            OrderInfoDto orderInfoDto = new OrderInfoDto();
            //暂时写死 快手的暂时只支持快手平台推的单子
            if(type == 6){
                orderInfoDto.setOrderChannelsType("KUAI_SHOU");
            }else{
                SourcePlatformEnum oct = SourcePlatformEnum.getByValue(e.getSourcePlatformCode());
                if (null == oct) {
                    orderInfoDto.setOrderChannelsType(SourcePlatformEnum.OTHERS.getValue());
                } else {
                    orderInfoDto.setOrderChannelsType(e.getSourcePlatformCode());
                }
            }

            orderInfoDto.setTradeOrderList(orderList);

            List<DeliveryItem> deliveryItems = finalDeliveryItemsMap.get(e.getCode());
            if (IterUtil.isEmpty(deliveryItems)) {
                log.error("找不到订单明细，订单标识：{}", e.getCode());
                deliveryService.updateFailureReasonOfGetWaybillCode(deliveryCodes, "找不到订单明细，订单标识：" + e.getCode(),groupCode);
                throw new ServiceException("找不到订单明细，订单标识：" + e.getCode());
            }
            List<Item> items = deliveryItems.stream().map(e1 -> {
                Item item = new Item();
                item.setName(e1.getGoodsName());
                item.setCount(e1.getQuantity().intValue());
                return item;
            }).collect(toList());

            PackageInfoDto packageInfoDto = new PackageInfoDto();
            packageInfoDto.setId(e.getId());
            packageInfoDto.setItems(items);
            //淘宝顺丰快递时，如下四个字段必填
            if (StrUtil.equalsAny(carriers.getOuterCode(),"SF","shunfeng")) {
                packageInfoDto.setGoodsDescription("奇门默认分类");
                packageInfoDto.setLength(1L);
                packageInfoDto.setWidth(1L);
                packageInfoDto.setHeight(1L);
            }


            AddressDto receiveAddress = new AddressDto();
            receiveAddress.setProvince(e.getReceiverProvince());
            receiveAddress.setCity(e.getReceiverCity());
            receiveAddress.setDistrict(e.getReceiverDistrict());
            receiveAddress.setDetail(e.getReceiverDetailAddress());

            UserInfoDto receiver = new UserInfoDto();
            receiver.setName(e.getReceiverName());
            receiver.setMobile(e.getReceiverMobile());
            receiver.setPhone(e.getReceiverMobile());
            receiver.setAddress(receiveAddress);
            receiver.setOaid(e.getOaid());

            TradeOrderInfoDto tradeOrderInfoDto = new TradeOrderInfoDto();
            tradeOrderInfoDto.setObjectId(e.getCode());
            switch (type) {
                //京东获取面单信息时，在TradeOrderInfoDto类里新增TradeOrderInfoDto.JdWaybillDTO内部类属性
                case 2:
                    dto.setSheetMerchantCode(shop.getPlatformShopCode());
                    dto.setMallMerchantCode(shop.getMerchantsCode());
                    TradeOrderInfoDto.JdWaybillDTO jdWaybillDTO = getJdWaybillDTO(e, carriers, dto.getMallMerchantCode());
                    tradeOrderInfoDto.setJdWaybillDTO(jdWaybillDTO);
                    break;
                //快手获取面单信息时，在TradeOrderInfoDto类里新增TradeOrderInfoDto.GetEbillOrderRequest内部类属性
                case 6:
                    TradeOrderInfoDto.GetEbillOrderRequest getEbillOrderRequest = getGetEbillOrderRequest(e, carriers, dto.getMallMerchantCode());
                    tradeOrderInfoDto.setGetEbillOrderRequest(getEbillOrderRequest);
                    break;
                case 4:
                    //抖音增加产品类型
                    if (StrUtil.isNotEmpty(carriers.getExpressType())) {
                        tradeOrderInfoDto.setProductType(carriers.getExpressType());
                    }
                    tradeOrderInfoDto.setUserId(-1L);
                    break;
                default:
                    tradeOrderInfoDto.setUserId(StrUtil.isNotBlank(e.getUserId()) ? Long.parseLong(e.getUserId()) : 0L);
            }

            tradeOrderInfoDto.setTemplateUrl(standardTemplateUrl);
            tradeOrderInfoDto.setOrderInfo(orderInfoDto);
            tradeOrderInfoDto.setPackageInfo(packageInfoDto);
            tradeOrderInfoDto.setRecipient(receiver);

            orderInfoDtos.add(tradeOrderInfoDto);
        });
        dto.setTradeOrderInfoDtos(orderInfoDtos);
        return dto;
    }

    private void hedan(Delivery e) {
        if(ObjectUtil.isNotEmpty(e) && StringUtils.isNotEmpty(e.getIsvCode())){
            String[] split = e.getIsvCode().split("，|,");
            e.setIsvCode(split[0]);
        }
    }

    @Async
    public Future<Boolean> batchGetWaybillCodeByDeliverys(ElectronicFaceSheetDTO dto, String branchCode, List<String> deliveryCodes) {

        ResultDO resultDO = arpaCloudUtil.getWaybillPrintData(dto, branchCode);
        log.info("从中台获取到的电子面单信息为,{}",JSONUtil.toJsonStr(resultDO));
        if (resultDO.getStatus() != 0) {
            JSONObject result = null;
            String msg = StrUtil.EMPTY;
            //异常信息封装在msg时
            if (null == resultDO.getData() && StrUtil.isNotBlank(resultDO.getMsg())) {
                deliveryService.updateFailureReasonOfGetWaybillCode(deliveryCodes, "获取面单异常，异常信息为：" + JSONUtil.toJsonStr(resultDO.getMsg()),branchCode);
                throw new ServiceException("获取面单异常，异常信息为：" + JSONUtil.toJsonStr(resultDO.getMsg()));
            }
            //异常信息封装在data时
            try {
                result = JSONUtil.parseObj(resultDO.getData());
                msg = (String) result.get("msg");
            } catch (Exception e) {
                //如果解析为JSONObject报异常，在尝试解析为List
                List<Map> resultMapList = JSONUtil.toList(JSONUtil.toJsonStr(resultDO.getData()), Map.class);
                if (IterUtil.isEmpty(resultMapList)){
                deliveryService.updateFailureReasonOfGetWaybillCode(deliveryCodes, "获取面单异常，异常信息为：" + JSONUtil.toJsonStr(resultDO.getData()),branchCode);
                throw new ServiceException("获取面单异常，异常信息为：" + JSONUtil.toJsonStr(resultDO.getData()));
                } else {
                msg = (String)resultMapList.get(NumConst.NUM_ZERO).get("msg");
                }
            }
            log.error("{}:{}", "获取面单失败：电子面单服务异常", msg);
            deliveryService.updateFailureReasonOfGetWaybillCode(deliveryCodes, "获取面单失败：电子面单服务异常" + msg,branchCode);
            throw new ServiceException("获取面单失败：电子面单服务异常" + msg);
        } else {
            List<ESSElectronicFaceSheetVO> voList = JSONUtil.toList(JSONUtil.toJsonStr(resultDO.getData()), ESSElectronicFaceSheetVO.class);

            for (ESSElectronicFaceSheetVO waybillCloudPrintResponse : voList) {
                String code = waybillCloudPrintResponse.getObjectId();
                String wayBillCode = waybillCloudPrintResponse.getWaybillCode();
                //JSONObject printData = JSONUtil.parseObj(waybillCloudPrintResponse.getPrintData());
                log.info("更新订单【{}】状态,面单号【{}】", code, wayBillCode);
                String routeCode = "";

                //JSONObject data = JSONUtil.parseObj(printData.get("data"));
                //if (null != data) {
                //    JSONObject routingInfo = JSONUtil.parseObj(data.get("routingInfo"));
                //    if (null != routingInfo) {
                //        if (null != routingInfo.get("routeCode")) {
                //            routeCode = routingInfo.get("routeCode").toString();
                //        }
                //    }
                //}
                //更新订单物流信息
                deliveryService.updateWayBillCode(code, wayBillCode, "", "", waybillCloudPrintResponse.getPrintData(), routeCode,branchCode);

            }
            List<String> success = voList.stream().map(ESSElectronicFaceSheetVO::getObjectId).collect(toList());

            // 如果没获取到面单号，则将状态更新为 待发货
            List<String> reduce = success.stream().filter(item -> !deliveryCodes.contains(item)).collect(toList());
            if (IterUtil.isNotEmpty(reduce)) {
                log.info("未获取到面单号,订单标识{}", reduce);
                deliveryService.updateFailureReasonOfGetWaybillCode(deliveryCodes, "未获取到面单号,订单标识：" + reduce,branchCode);
                throw new ServiceException("未获取到面单号,订单标识：" + reduce);
            }
        }

        return new AsyncResult(true);
    }


    public TradeOrderInfoDto.GetEbillOrderRequest getGetEbillOrderRequest(Delivery delivery, Carrier carriers, String mallMerchantCode) {
        TradeOrderInfoDto.GetEbillOrderRequest getEbillOrderRequest = new TradeOrderInfoDto.GetEbillOrderRequest();
        //商家编码
        getEbillOrderRequest.setMerchantCode(carriers.getVendorCode());
        //商家名称
        getEbillOrderRequest.setMerchantName(carriers.getVendorName());
        //包裹总数量
        getEbillOrderRequest.setTotalPackageQuantity(1L);
        //区分物流公司类型 直营和加盟
        if(StrUtil.equalsAny(carriers.getOuterCode(),"POSTB","EMS","JD","SF")){
            getEbillOrderRequest.setType("0");
            //直营
            if(StrUtil.equalsAny(carriers.getOuterCode(),"SF","EMS","POSTB")){
                //面单扩展信息
                getEbillOrderRequest.setExtData(carriers.getExtData());
                if(StrUtil.equalsAny(carriers.getOuterCode(),"SF")){
                    getEbillOrderRequest.setPayMethod(Integer.valueOf(carriers.getExpressPayMethod()));
                }
            }
            if(StrUtil.equalsAny(carriers.getOuterCode(),"JD")){
                //expressProductCode：物流产品
                getEbillOrderRequest.setExpressProductCode(carriers.getExpressProductCode());
                //payMethod（付款方式）
                getEbillOrderRequest.setPayMethod(Integer.valueOf(carriers.getExpressPayMethod()));
                //（要求上门取件时间）：
                long timestamp = delivery.getGmtCreated().toInstant(ZoneOffset.ofHours(8)).toEpochMilli();
                long l = 3600000L * 12;
                getEbillOrderRequest.setReserveTime(timestamp + l);
                //要求上门取件时间结束时间
                long m = 3600000L * 24;
                getEbillOrderRequest.setReserveEndTime(timestamp + m);
            }
            //客户编码=月结卡号
            getEbillOrderRequest.setSettleAccount(carriers.getCustomerCode());
        }else{
            getEbillOrderRequest.setType("1");
            //加盟
            //网点编码
            getEbillOrderRequest.setNetSiteCode(carriers.getBranchCode());
            //网点名称
            getEbillOrderRequest.setNetSiteName(carriers.getBranchName());
        }
        return getEbillOrderRequest;
    }

    public TradeOrderInfoDto.JdWaybillDTO getJdWaybillDTO(Delivery delivery, Carrier carriers, String mallMerchantCode) {
        TradeOrderInfoDto.JdWaybillDTO jdWaybillDTO = new TradeOrderInfoDto.JdWaybillDTO();
        //运单类型：1-普通运单；2-生鲜；3-航空
        jdWaybillDTO.setWaybillType(NUM_ONE);
        //所需运单的数量，顺丰只能传1，非顺丰快递公司最多只能传99
        jdWaybillDTO.setWaybillCount(NUM_ONE);
        //承运商编码（与providerId必填一个）,这里只填承运商编码
        jdWaybillDTO.setProviderCode(carriers.getOuterCode());
        jdWaybillDTO.setProviderId(carriers.getProviderId());
        //平台订单号，即pop订单号，脱敏项目必须穿真实的京东pop订单号
        jdWaybillDTO.setPlatformOrderNo(delivery.getIsvCode());
        //商家编码，商家编码，是用POP商家ID
        jdWaybillDTO.setVendorCode(carriers.getVendorCode());
        //商家名称
        jdWaybillDTO.setVendorName(carriers.getVendorName());
        //承运商发货网点编码
        jdWaybillDTO.setBranchCode(carriers.getBranchCode());
        //商家自有订单号
        jdWaybillDTO.setVendorOrderCode(delivery.getCode());
        //销售平台；0010001代表京东平台下的订单
        jdWaybillDTO.setSalePlatform("0010001");
        jdWaybillDTO.setWeight(BigDecimal.ONE);
        jdWaybillDTO.setVolume(BigDecimal.ONE);
        //承诺时效类型；无时效默认传0
        jdWaybillDTO.setPromiseTimeType(NumConst.NUM_ZERO);
        jdWaybillDTO.setGoodsMoney(BigDecimal.ONE);
        jdWaybillDTO.setPayType(NumConst.NUM_ZERO);
        jdWaybillDTO.setShouldPayMoney(BigDecimal.ZERO);
        jdWaybillDTO.setNeedGuarantee(false);
        jdWaybillDTO.setGuaranteeMoney(BigDecimal.ZERO);
        jdWaybillDTO.setPin(StrUtil.EMPTY);
        jdWaybillDTO.setSalePlat("0010001");
        //商家编码/青龙业主号/配送编码/月结编码
        jdWaybillDTO.setCustomerCode(mallMerchantCode);
        jdWaybillDTO.setOrderId(delivery.getCode());
        jdWaybillDTO.setThrOrderId(delivery.getCode());
        jdWaybillDTO.setPackageCount(NUM_ONE);
        //商家结算编码，直营承运商必填
        if (StrUtil.isNotEmpty(carriers.getCustomerCode())) {
            jdWaybillDTO.setSettlementCode(carriers.getCustomerCode());
        }
        //快递费付款方式(顺丰必填)，1:寄方付 2:收方付 3:第三方付(京东)
        if (StrUtil.isNotEmpty(carriers.getExpressPayMethod())) {
            jdWaybillDTO.setExpressPayMethod(carriers.getExpressPayMethod());
        }
        //快件产品类别，目前顺丰使用，后续可根据承运商自己定义 。1-顺丰标快；2-顺丰特惠(京东）
        if (StrUtil.isNotEmpty(carriers.getExpressType())) {
            jdWaybillDTO.setExpressType(carriers.getExpressType());
        }

        return jdWaybillDTO;
    }

    @Transactional(rollbackFor = {Exception.class})
    public Result changeCarrier(List<String> deliveryCodes, String carrierCode) {
        String groupCode = UserUtil.getBranchCode();
        //校验订单 + 处理订单（去掉面单号  更改订单数据）
        deliveryService.checkDelivery(deliveryCodes,carrierCode);
        try {
            //获取面单号
            String msg = this.batchGetWaybillCode(deliveryCodes,groupCode);
        }catch (Exception e){
            e.printStackTrace();
        }
        return Result.ok();
    }
/*
    public static void main(String[] args) {

        String dailyUrl = "http://link.cainiao.com/gateway/link.do";
        String dailyAppKey = "403966";
        String dailySecretKey="95781KG41Nwh66wBs9xm524ZB7cZ8411";
        String dailyToken="TkpNSlZadDl5VnVhZ1llRTRqT3NUeEZwb3lEWnY0MjBPZWlYcitOWmhnOCtFdDJZMWdrZDN1RVk3UHQxNFpadw==";

        PacClient client = new PacClient(dailyAppKey, dailySecretKey, dailyUrl);
        SendSysParams params = new SendSysParams();
        params.setFromCode(dailyToken);
   *//*     TmsWaybillDiscardRequest request = new TmsWaybillDiscardRequest();
        //配送公司编码
        request.setCpCode("YTO");
        request.setWaybillCode("YT5485914254104");

        TmsWaybillDiscardResponse tmsWaybillDiscardResponse = client.send(request, params);
        if(!tmsWaybillDiscardResponse.isSuccess()){
            log.error("电子面单取消失败: errorCode:" + tmsWaybillDiscardResponse.getErrorCode() + ",errorMessage:" + tmsWaybillDiscardResponse.getErrorMsg());
        }*//*

        CloudprintStandardTemplatesRequest request1 = new CloudprintStandardTemplatesRequest();
        request1.setCpCode("YTO");
        CloudprintStandardTemplatesResponse cloudprintStandardTemplatesResponse = client.send(request1, params);
        if(cloudprintStandardTemplatesResponse.isSuccess()){
            List<StandardTemplateResult> obj =  cloudprintStandardTemplatesResponse.getData();
            System.out.println(JSONUtil.toJsonStr(obj));
        }
    }*/

    /**
     * 获取倒数第几位字符
     * @author rfwang
     * @date 2022/3/24 15:33
     * @param originStr
     * @param n
     */
    private String getNChar(String originStr,int n) {
        return originStr.substring(originStr.length()-n, originStr.length()-n+1);
    }

    /**
     * 处理erp推单在isvCode添加字符情况
     *
     * @param delivery 订单
     */
    public void handleIsvCode(Delivery delivery,Map<String,Object> shipmentMap){
        String pattern = "[A-Z]";
        if (MapUtil.isNotEmpty(shipmentMap) && ErpTypeEnum.JI_KE_YUN.getValue().equals((String)shipmentMap.get("erpCode"))) {
            //吉客云isvCode会以A结尾 或者 以 -1 为结尾
            //1.尾号是大写的A-Z结尾
            if (StrUtil.isNotEmpty(delivery.getIsvCode()) && Pattern.matches(pattern,getNChar(delivery.getIsvCode(),1))) {
                delivery.setIsvCode(delivery.getIsvCode().substring(0,delivery.getIsvCode().length()-1));
                return;
            }
            //2.倒数第三位以大写A-Z结尾。例如A-1
            if (StrUtil.isNotEmpty(delivery.getIsvCode()) && Pattern.matches(pattern,getNChar(delivery.getIsvCode(),3))) {
                delivery.setIsvCode(delivery.getIsvCode().substring(0,delivery.getIsvCode().length()-3));
                return;
            }
            //根据倒数第二位是否为"-"进行判断，可以兼顾-1到-9的情况
            if (StrUtil.isNotEmpty(delivery.getIsvCode()) && CommonConst.SEPARATOR.equals(getNChar(delivery.getIsvCode(),2))) {
                delivery.setIsvCode(delivery.getIsvCode().substring(0,delivery.getIsvCode().length()-2));
            }

        }
    }



}
